DearMiku

Opengl ES 3.0 on iOS--- 统一变量(Uniform)和统一变量块(UBO)

字数统计: 1.1k阅读时长: 4 min
2017/11/28 Share

简介

Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。

首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。
第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。

单独统一变量

声明

uniform vec3 color

赋值

1
2
3
4
5
//获取指定统一变量的location
int vertexColorLocation = glGetUniformLocation(_program, "test");

//为vec3 的统一变量 赋值
glUniform3f(vertexColorLocation, 0.0f, 1.0f, 0.0f);

赋值函数是根据 统一变量类型的不同而调整的.其中函数名中包含数字(1、2、3、4)表示接受这个数字个用于更改uniform变量的值,i表示32位整形,f表示32位浮点型,ub表示8位无符号byte,ui表示32位无符号整形,v表示接受相应的指针类型(或者就是传入的是数组)。

glUniform1f(GLint locaation,GLFloat x) 表示 float类型
glUniform2f(GLint locaation,GLFloat x,GLFloat y) 表示 二位向量 分量类型为float
glUniform1fv(GLint locaation,GLSize count,const GLfloat* value) float类型指针
glUniformMatrix4x3(Glint location,GLsizei count,GLboolean transpose,const GLfloat* value) 表示为 4x3矩阵. 参数: transpose 表示是否采用 行优先顺序(GL_TRUE)

UBO

UBO(Uniform Buffer Object)是用来存储着色语言中Uniform类型变量的缓冲区对象,使用UBO可以让uniform变量在不同的着色语言程序中实现共用,也可以在着色语言程序中实现uniform类型变量的设置与更新。

提到UBO就必须要提到着色语言GLSL中的Uniform Blocks,它将众多的Uniform类型的变量集中在一起进行统一的管理,对于需要大量Uniform类型变量的程序可以显著地提高性能。(有点像全局版的VBO)

原理

UBO示意图

在显存中创建缓存对象(Buffer),在buffer中存储统一变量数据, 将Buffer与 指定的point绑定, 将统一变量缓冲区的索引 和 point绑定. 这样通过point 将变量 和 缓存 连接.

设置UBO

1
2
3
4
//统一变量块
layout (std140) uniform colorBlock{
vec4 cc;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
GLuint blockid,bufferid;
GLint blocksize;
GLint point = 1;

// 统一变量数据
GLfloat blockData[] = {
1.0f,1.0f,1.0f,1.0f
};

//获取统一变量块索引
blockid = glGetUniformBlockIndex(_program, "colorBlock");

//获取统一变量块大小
glGetActiveUniformBlockiv(_program, blockid, GL_UNIFORM_BLOCK_DATA_SIZE, &blocksize);

//将变量索引 和 point 绑定
glUniformBlockBinding(_program, blockid, point);

//创建与绑定缓冲区
glGenBuffers(1, &bufferid);
glBindBuffer(GL_UNIFORM_BUFFER, bufferid);

//向缓冲区中赋值
glBufferData(GL_UNIFORM_BUFFER, blocksize, blockData, GL_DYNAMIC_DRAW);

//将UBO 和 point 绑定
glBindBufferBase(GL_UNIFORM_BUFFER, point, bufferid);

修改UBO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GLfloat uploadData[] = {
0.0f,0.0f,1.0f,1.0f
};

// 绑定当然统一变量块的 buffer
glBindBuffer(GL_UNIFORM_BUFFER, bufferid);

//获取统一变量块 中 指定变量的 偏移量
const GLchar *names[] = {"cc"};
GLuint indices[1];
glGetUniformIndices(_program, 1, names, indices);
GLint offset[1];
glGetActiveUniformsiv(_program, 1, indices, GL_UNIFORM_OFFSET, offset);
glBufferSubData(GL_UNIFORM_BUFFER, offset[0], blocksize, uploadData);

函数补充

1, glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* const *uniformNames, GLuint* uniformIndices)
该函数用于获取统一变量块中 变量们的索引 参数:

program 程序对象
uniformCount 变量名称数组的元素数量
uniformNames 变量名称数组
uniformIndices 用于接受变量索引的数组

2,glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
该函数用于 通过变量索引 查询变量信息. 参数:

program 程序对象
uniformCount 变量数量
uniformIndices 变量索引数组
pname 表示要查询变量的那个属性 GL_UNIFORM_OFFSET(变量偏移量) GL_UNIFORM_SIZE(变量大小) GL_UNIFORM_NAME_LENGTH(变量名长度) GL_UNIFORM_TYPE(变量类型)….
params 接受查询结果的数组

注意

着色语言编译优化

如果你声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它.

UBO限定符

在UBO中,针对不同的限定符 还存在不同的字节补齐的情况.所以获取偏移量,大小最好还是通过查询进行,避免自己计算出现错误.

这是 std140(标准统一变量块布局)限定符的内存分配情况:

std140

其他的限定符 在我学了之后会补上~

CATALOG
  1. 1. 简介
  2. 2. 单独统一变量
    1. 2.1. 声明
    2. 2.2. 赋值
  3. 3. UBO
    1. 3.1. 原理
    2. 3.2. 设置UBO
    3. 3.3. 修改UBO
      1. 3.3.1. 函数补充
  4. 4. 注意
    1. 4.1. 着色语言编译优化
    2. 4.2. UBO限定符